feat: add EVM API support, tx pipeline, ERC20, and precompiles#14
Conversation
Reviewed the EVM migration module, tx building refactor, crypto/ethsecp256k1 replacement, and dependency bumps. Found 2 issues to address before merging.
Mention @roomote in a comment to request specific changes to this pull request or fix all unresolved issues. |
- Add EVMigration module client with query operations (Params,
MigrationRecord, MigrationRecordByNewAddress, MigrationEstimate,
MigrationStats) and wire it into blockchain.Client
- Refactor tx building into composable stages:
- PrepareTx: builds unsigned tx builder and resolves signer metadata
- SignPreparedTx: signs a prepared builder with explicit signer info
- BuildAndSignTxWithOptions: end-to-end build+sign with TxBuildOptions
- BroadcastAndWait: broadcast + wait-for-inclusion convenience method
- Support explicit AccountNumber/Sequence, GasLimit, SkipSimulation,
FeeAmount, and multi-message transactions via TxBuildOptions
- Replace local ethsecp256k1 implementation with cosmos/evm upstream
(github.com/cosmos/evm/crypto/ethsecp256k1), removing
pkg/crypto/ethsecp256k1/ package
- Register additional module interfaces in NewDefaultTxConfig (bank,
staking, distribution, authz, claim, supernode) for proper tx
encoding/decoding
- Bump dependencies:
- Go 1.25.5 -> 1.26.1
- cosmos-sdk v0.53.5 -> v0.53.6
- cometbft v0.38.20 -> v0.38.21
- grpc v1.77.0 -> v1.79.2
- LumeraProtocol/lumera v1.10.0 -> v1.11.0
- Add github.com/cosmos/evm v0.6.0
- Add comprehensive tests for tx building (manual signer info,
queried account info + simulation, default message sizes)
- Apply config defaults (MaxRecvMsgSize/MaxSendMsgSize) in base.New
- Remove deprecated blockchain/messages.go
- Update docs and copilot-instructions for Go 1.26.1
- Register evmigration interfaces in the default tx config so MsgClaimLegacyAccount / MsgMigrateValidator can be encoded and signed. - Add ClaimLegacyAccountTx / MigrateValidatorTx helpers plus NewMsgClaimLegacyAccount / NewMsgMigrateValidator constructors and MigrationResult on EVMigrationClient. - Add EVMAddressFromKey to derive a 0x EIP-55 address for eth_secp256k1 keys; promote go-ethereum to a direct dependency.
Wire up x/erc20, x/feemarket, x/precisebank, and x/vm RegisterInterfaces so SDK consumers can encode and sign EVM-module messages (e.g. MsgConvertERC20, MsgEthereumTx) through the standard tx pipeline. Pulls a handful of new indirect deps via go mod tidy.
bufconn-backed fake QueryServer exercises Params, MigrationRecord, MigrationRecordByNewAddress, MigrationEstimate, and MigrationStats, plus a NotFound path. Adds sanity checks for the new NewMsgClaimLegacyAccount / NewMsgMigrateValidator constructors.
- Document EVMigration query + tx helpers and MigrationResult. - Note expanded BuildAndSignTx surface (Options, Prepare/Sign split, BroadcastAndWait, GetTxsByEvents). - Document EVMAddressFromKey and the EVM-module interface registrations in NewDefaultTxConfig. - Add a tutorial for the legacy account / validator migration flow.
Sketches the opinionated client layout for x/vm, x/erc20, x/feemarket, and x/precisebank, plus Ethereum signing helpers in pkg/crypto, config additions for EVMChainID/EVMDenom, and a phased build sequence. No code changes.
Anchor decisions in lumera/docs/evm-integration: - Note the shared nonce/sequence counter and its impact on nonce caching. - Default EVMDenom to alume; add EVMValueUnit and Wei/ULume helpers for the 6 <-> 18 decimal boundary (precisebank, 10^12 factor). - Tighten Bech32ToEVM contract: reject legacy secp256k1 cosmos addresses whose derivation is not reversible. - Set GasTipCap default from feemarket.Params.MinGasPrice and call out the ExtensionOptionsEthereumTx routing on Lumera's dual-route ante. - New pkg/evm/precompiles section covering Lumera's custom precompiles (action 0x0901, supernode 0x0902, wasm 0x0903) plus standard precompile address constants. - Expand build sequence to a dedicated precompiles phase; add open questions on the precompile-vs-msg choice rule, Lumera defaults option group, and ABI vendoring strategy.
- ethaddr.go: EVMToBech32 / Bech32ToEVM for byte-level encoding plus Wei / ULume / ULumeDecToWei to bridge the 6 <-> 18 decimal boundary defined by x/precisebank (10^12 factor). - ethsign.go: SignEthereumTx signs a go-ethereum tx using the keyring's eth_secp256k1 key and the latest EIP-155 signer for the EVM chain ID. WrapAsMsgEthereumTx packages a signed tx as MsgEthereumTx; RecoverSender exposes the recovered address for verification. Round-trip tests cover sign -> recover, MsgEthereumTx wrap, rejection of cosmos secp256k1 keys, decimal conversions, and bech32 length guards. Phase 1 of docs/design/0001-cosmos-evm-api.md.
- EVMClient (x/vm): Code, Storage, Balance (alume), EthAccount, CosmosAccount, Params, BaseFee, Config, GlobalMinGasPrice, EthCall, EstimateGas, TraceTx. EthCall/EstimateGas marshal TransactionArgs JSON for the cosmos/evm gRPC contract. - FeeMarketClient (x/feemarket): Params, BaseFee (ulume decimal), BlockGas. Companion to EVMClient.BaseFee which returns alume. - PreciseBankClient (x/precisebank): Remainder, FractionalBalance. - All three wired onto blockchain.Client via the existing constructor. Tests stub the QueryClient interface directly instead of going through bufconn, because the default grpc proto v2 codec panics on gogoproto customtype fields (sdkmath.Int / LegacyDec) in EVM responses. Tests cover Lumera-flavored defaults (BaseFee 0.0025 ulume/gas, etc). Phase 2 of docs/design/0001-cosmos-evm-api.md.
EVMClient gains tx helpers signed with the keyring's eth_secp256k1 key and routed through Cosmos EVM's MsgEthereumTx + ExtensionOptionsEthereumTx envelope: - SendEthereumTransaction: resolves nonce (EthAccount), gas (EstimateGas + 20% buffer), tip/fee caps (feemarket MinGasPrice and BaseFee*2+tip), signs the DynamicFeeTx (EIP-1559), wraps as MsgEthereumTx, and broadcasts via the base client. - DeployContract: contract creation sugar; returns the CREATE address derived from sender+nonce. - CallContract: read-only EthCall sugar. - RawEthereumTx: broadcast a pre-signed go-ethereum tx unchanged (hardware wallet path). - buildEthereumTxBytes: shared envelope encoder (callable from tests). Configuration additions plumbed end-to-end: - blockchain/base/Config gains EVMChainID, EVMNativeDenom (ulume), EVMExtendedDenom (alume), EVMGasTipCap, EVMGasFeeCap. - client/config mirrors them; client.WithEVMChainID / WithEVMNativeDenom / WithEVMExtendedDenom / WithEVMGasCaps expose them via Option. - client.New copies the EVM fields into blockchain.Config. Guards: - validateTxBuildOptions rejects MsgEthereumTx in the cosmos signing pipeline so callers cannot accidentally double-sign. - SendEthereumTransaction / RawEthereumTx error when EVMClient lacks a Client backref or EVMChainID is unset. Tests cover envelope round-trip via the standard TxDecoder, the CREATE address derivation, and the new guards. Phase 3 of docs/design/0001-cosmos-evm-api.md.
- ERC20Client (x/erc20): TokenPairs (paginated), TokenPair, Params plus message constructors NewMsgConvertCoin / NewMsgConvertERC20 / NewMsgRegisterERC20 / NewMsgToggleConversion. - Tx helpers on blockchain.Client: ConvertCoinToERC20 (cosmos coin -> ERC20, signed via the bech32 sender derived from the keyring) and ConvertERC20ToCoin (ERC20 -> cosmos coin, signed via the 0x sender derived from eth_secp256k1). Plus RegisterERC20Tx and ToggleConversionTx for governance flows. All four use the standard cosmos signing pipeline (BuildAndSignTx) — no Ethereum signing. - ConversionResult result type and broadcastConversion shared helper. - ABI sugar (erc20_abi.go): hand-rolled minimal ERC20 JSON (balanceOf, totalSupply, allowance, name, symbol, decimals) compiled at init. Erc20Balance / Erc20TotalSupply / Erc20Allowance / Erc20Metadata pack calldata and route through EVMClient.CallContract. Tests cover queries, message constructors, and ABI pack/unpack. Phase 4 of docs/design/0001-cosmos-evm-api.md.
- pkg/evm/precompiles exposes vendored Hardhat artifact ABIs (action, supernode, wasm) via go:embed and parses them at init. Also exports Lumera custom precompile addresses (0x0901 / 0x0902 / 0x0903) and the eight standard cosmos/evm precompile addresses as named constants. Generic PackCall / UnpackReturn helpers wrap the go-ethereum abi package. - blockchain.PrecompileClient: a single generic wrapper that holds a precompile address + parsed ABI and routes calls through EVMClient. Call(ctx, method, args...) does a read-only EthCall and unpacks the outputs; Send(ctx, method, opts, args...) signs and broadcasts a state-changing call via SendEthereumTransaction. - EVMClient grows Action / Supernode / Wasm fields wired at construction to the corresponding precompile addresses + ABIs. Callers invoke any method on any precompile without compiling Solidity bindings. ABI artifacts are Hardhat-format JSON with an `abi` field; the loader falls back to a bare array if a vendor switches formats later. Tests verify the embedded ABIs parse, exposed method names match the docs, and the PrecompileClient guards against missing backref / unknown method. Phase 5 of docs/design/0001-cosmos-evm-api.md. Typed wrappers for specific methods (RequestCascade, RegisterSupernode, etc.) are out of scope for v1 — callers compose them with PackCall and the published ABI.
- API.md gains entries for EVMClient / ERC20Client / FeeMarketClient / PreciseBankClient and the pkg/evm/precompiles package, plus new client.WithEVM* options. - DEVELOPER_GUIDE.md adds tutorials 8-10: - Sending an Ethereum-format transaction (configuration + Wei helper). - ERC20 conversion (ConvertCoinToERC20 + Erc20Balance ABI sugar). - Invoking a Lumera precompile via the generic Call/Send wrappers. Existing tutorials renumbered (SuperNodes is now 11). - examples/evm-transfer is a runnable CLI that signs and broadcasts an EIP-1559 transfer using an eth_secp256k1 key, prints the eth tx hash, cosmos tx hash, height, and gas used. Phase 6 of docs/design/0001-cosmos-evm-api.md. Phase 7 (EIP-712, nonce tracker, fee-market cache) remains.
- DeployContract: resolve and pin the nonce before broadcast and derive the CREATE address from it directly. Eliminates the race in the old post-broadcast EthAccount.Nonce-1 path. - resolveEVMDenoms: fall back to querying x/vm Params for native and extended denoms when Config leaves them empty. - resolveMinGasTipCap: pull the default tip cap from feemarket.Params.MinGasPrice (ulume decimal) and scale to alume via ULumeDecToWei, instead of GlobalMinGasPrice. - buildEthereumTxBytes: require a non-empty extended denom; falling back to the native denom silently produced wrong-denom fees. - Tighten ABI tests: wasm.execute is phase-1 non-payable, supernode.registerSupernode keeps bech32 string args, action fees stay uint256. Plus tests for the new gas-cap and denom-fallback paths. - Docstring polish in base/Config and ethsign.WrapAsMsgEthereumTx.
- DEVELOPER_GUIDE.md is now a one-page index that points to topical
guides under docs/guides/.
- Split into six self-contained sections:
getting-started.md install, config, factory, troubleshooting
crypto.md keyring, key types, address derivation, eth signing
actions.md x/action + x/supernode queries and tx helpers
cascade.md upload/download/events/stepwise flow
ica.md ICA controller + lower-level packet helpers
evm.md x/vm, x/erc20, x/feemarket, x/precisebank,
custom precompiles, x/evmigration
- API.md gains a topic-to-guide quick-link table at the top.
New examples for the EVM surface:
- examples/evm-balance read-only: balance (alume + ulume), nonce,
base fee, min gas price, precisebank fractional.
- examples/erc20-convert ConvertCoinToERC20 / ConvertERC20ToCoin both
directions, optionally prints the post-tx
ERC20 balance via the ABI sugar.
- examples/precompile-action invokes the action precompile (0x0901) for
both read (getParams) and write (approveAction).
`go test ./...` is green; all four EVM-era examples compile under `go build`.
- Comment out local supernode replace in go.mod so module consumers are not broken by a path-based replace directive. - Replace int64(gas) cast in resolveFeeAmount with sdkmath.NewIntFromUint64 to avoid signed overflow when callers pass a large user-controlled GasLimit via TxBuildOptions. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
Addressed the review feedback and pushed commit fc59013.
Validation: go test ./... and go vet ./... pass. |
|
There was a problem hiding this comment.
Pull request overview
This PR introduces first-class Cosmos EVM support across the SDK, spanning configuration, crypto/keyring integration, EVM module clients, transaction construction/signing/broadcasting, ERC20 conversions, and Lumera precompile tooling, alongside new examples and expanded documentation.
Changes:
- Added embedded Lumera precompile ABIs + generic pack/unpack helpers and wired typed
PrecompileClientwrappers underBlockchain.EVM.*. - Introduced EVM-focused crypto helpers (0x address derivation, bech32↔EVM conversion, 6↔18 decimal bridging, Ethereum tx signing/wrapping).
- Extended client and base tx infrastructure (EVM config options + tx pipeline refactor) and added EVM/erc20/feemarket/precisebank/evmigration module clients, docs, examples, and a v1.2.0 changelog entry.
Reviewed changes
Copilot reviewed 51 out of 52 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| pkg/evm/precompiles/precompiles.go | Defines precompile addresses, embeds Hardhat ABIs, parses ABIs at init, and provides pack/unpack helpers. |
| pkg/evm/precompiles/precompiles_test.go | Validates embedded ABIs and precompile address constants; sanity checks key methods/signatures. |
| pkg/evm/precompiles/abi/action.json | Embedded Action precompile ABI artifact. |
| pkg/evm/precompiles/abi/supernode.json | Embedded Supernode precompile ABI artifact. |
| pkg/evm/precompiles/abi/wasm.json | Embedded Wasm precompile ABI artifact. |
| pkg/crypto/keyring.go | Switches to cosmos/evm ethsecp256k1 support; registers additional module interfaces in tx config. |
| pkg/crypto/ethsign.go | Adds Ethereum-format tx signing, MsgEthereumTx wrapping, and sender recovery helpers. |
| pkg/crypto/ethsign_test.go | Tests eth tx signing, sender recovery, and MsgEthereumTx wrapping behavior. |
| pkg/crypto/ethsecp256k1/ethsecp256k1.go | Removes the local ethsecp256k1 implementation in favor of cosmos/evm. |
| pkg/crypto/ethaddr.go | Adds bech32↔EVM address conversion and ulume↔alume (wei-like) helpers. |
| pkg/crypto/ethaddr_test.go | Tests address conversion and ulume↔alume conversion edge cases. |
| pkg/crypto/crypto_test.go | Updates tests to assert against cosmos/evm ethsecp256k1 key type. |
| pkg/crypto/address.go | Adds EVMAddressFromKey for deriving 0x addresses from eth_secp256k1 keyring entries. |
| go.mod | Bumps Go version and pins/updates dependencies for cosmos/evm and related stacks (including go-ethereum fork replace). |
| examples/precompile-action/main.go | Example CLI for read/write Action precompile calls via PrecompileClient. |
| examples/ica-request-verify/main.go | Updates example to use cosmos/evm ethsecp256k1 package. |
| examples/evm-transfer/main.go | Example CLI for sending EIP-1559 txs via the SDK EVM pipeline. |
| examples/evm-balance/main.go | Example CLI for querying EVM-side balance/nonce/base fee/min gas price and precisebank fractional balance. |
| examples/erc20-convert/main.go | Example CLI for coin↔ERC20 conversion flows. |
| docs/guides/ica.md | Adds a dedicated ICA guide. |
| docs/guides/getting-started.md | Adds a focused getting-started guide covering config, client creation, and examples. |
| docs/guides/evm.md | Adds an EVM integration guide (queries, txs, ERC20, precompiles, migration). |
| docs/guides/crypto.md | Adds crypto guide for key types, keyring usage, address derivation, and eth signing helpers. |
| docs/guides/cascade.md | Adds focused Cascade guide. |
| docs/guides/actions.md | Adds focused Actions/Supernodes guide. |
| docs/DEVELOPER_GUIDE.md | Refactors developer guide into an index linking the focused guides. |
| docs/API.md | Expands API overview with EVM/erc20/precompile/migration surfaces and links to guides. |
| client/options.go | Adds EVM-related client.With... options (chain ID, denoms, gas caps). |
| client/config/config.go | Extends client config with EVM-related fields. |
| client/client.go | Wires EVM config through to the blockchain client initialization. |
| CHANGELOG.md | Adds a v1.2.0 entry documenting the EVM feature set and related changes. |
| blockchain/precompiles.go | Implements PrecompileClient wrapper for generic call/send against precompiles. |
| blockchain/precompiles_test.go | Unit tests for basic PrecompileClient behavior and error paths. |
| blockchain/precisebank.go | Adds x/precisebank query wrapper client. |
| blockchain/messages.go | Removes deprecated messages placeholder file. |
| blockchain/feemarket.go | Adds x/feemarket query wrapper client. |
| blockchain/evmigration.go | Adds x/evmigration query client, message constructors, and tx helpers. |
| blockchain/evmigration_test.go | Tests evmigration query wrappers and message constructors. |
| blockchain/evm_tx_test.go | Tests EVM tx bytes building and address derivation helpers used by EVM tx flow. |
| blockchain/evm_test.go | Tests EVM query wrappers, gas cap resolution, denom resolution, and response decoding helpers. |
| blockchain/erc20.go | Adds x/erc20 query client, message constructors, and conversion tx helpers. |
| blockchain/erc20_test.go | Tests ERC20 queries and message constructors; validates ABI packing/unpacking behavior. |
| blockchain/erc20_abi.go | Adds minimal ERC20 ABI + read-only ERC20 helpers via EVM eth_call. |
| blockchain/client.go | Wires new module clients (EVM, ERC20, FeeMarket, PreciseBank, EVMigration) and precompile wrappers. |
| blockchain/base/tx.go | Refactors tx building into PrepareTx/SignPreparedTx with TxBuildOptions and adds BroadcastAndWait. |
| blockchain/base/tx_test.go | Adds coverage for new tx build options behavior and overflow regression. |
| blockchain/base/config.go | Extends base blockchain config with EVM-related configuration fields. |
| blockchain/base/client.go | Applies config defaults earlier and exposes getters for keyring/keyname/config. |
| .github/copilot-instructions.md | Updates internal guidance to Go 1.26.2. |
|
Reviewed this end to end. The EVM surface is generally well structured, and the local gates are clean on the PR head
I would hold merge until these are fixed:
One non-blocking note: before tagging this SDK, I would still like to see a devnet smoke for the actual EVM broadcast path ( |
# Conflicts: # go.sum
|
Addressed the a-ok123 audit items in commit 1d255a2. Per issue:
Verification:
Note: the a-ok123 audit was a top-level PR comment rather than inline review threads, so there are no per-issue GitHub resolve checkboxes to mark. The remaining inline review threads that were fixed were commented on and marked resolved. |
|
Follow-up after the request to ensure tests cover every fixed issue: pushed b3d28d1 with additional regression coverage. Added/confirmed coverage now includes:
The rest of the fixed behavioral items already have regression coverage in the same PR: legacy key URL unpacking, raw proto EVM response decoding, MsgEthereumTx guard behavior, signer/recovered-sender validation, CallContract sender derivation errors, RawEthereumTx chain ID validation, included tx code checking, EVM extension option assertion, happy-path EVM send, and gogoproto numeric gRPC round-tripping. Doc-only clarifications (F04/F16) are covered by docs/godoc changes rather than runtime tests. |
|
Audited the remaining review comments beyond the a-ok123 table. Status:
All resolvable review threads are currently resolved. The remaining items are top-level PR comments, which GitHub does not expose as resolvable threads. |
Address issues found during the evm-support branch audit: - keyring: ImportKey now verifies an existing key was derived from the supplied mnemonic, instead of silently returning the stored key's address when a different mnemonic is imported under the same name. - evm: buildEthereumTxBytes rejects an empty native denom (previously panicked in sdk.NewCoin); resolveEVMDenoms errors are now actionable. - evm: DeployContract returns the zero address + error when the constructor reverts (VmError) instead of an address with no contract. - erc20: balance/supply/allowance/metadata reads return a clear error on empty return data rather than a cryptic ABI unmarshal error. - tx: resolveGasLimit propagates simulation errors instead of silently falling back to a fixed gas limit that can under-gas the tx. - evm: guard GasUsed int64->uint64 cast; feemarket BlockGas rejects negative gas; AddressFromKey guards an empty derived address. - client: forward AccountHRP/FeeDenom/GasPrice from the client config into the blockchain config (With* options added). - wait-tx: surface the subscriber error when the poller also fails. - precompiles: parseHardhatABI handles an explicit null abi field. Adds regression tests for each behavioral change. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- README: add EVM to Features, list the EVM/ICA examples, and link the topic guides. - API.md + getting-started: document the new AccountHRP/FeeDenom/GasPrice config fields and With* options. - crypto guide: note ImportKey rejects a mismatched mnemonic for an existing key name. - evm guide: note DeployContract errors (zero address) on constructor revert. - CHANGELOG: record the new client options and the audit-fix behaviors (ImportKey verification, ERC20 empty-return errors, simulation-error propagation, deploy revert handling, denom/gas guards, wait-tx errors). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Summary
Adds the Lumera EVM API surface and supporting transaction/crypto infrastructure. This branch introduces EVM migration helpers, Ethereum-format transaction signing/broadcast, read-only cosmos/evm clients, ERC20 conversion and ABI helpers, Lumera precompile wrappers, docs, examples, and a changelog entry for the new release.
Major Changes
EVM Migration Module
EVMigrationClientwith query helpers for params, migration records, migration estimates, and migration stats.blockchain.Client.EVM Addressing, Signing, and Transaction Pipeline
MsgEthereumTxwrapping helpers.EVMClienttransaction helpers for EIP-1559 Ethereum-format txs, raw signed tx broadcast, contract deployment, contract calls, nonce resolution, gas estimation, and fee cap resolution.MsgEthereumTx, which must use the EVM path.Read-Only EVM Module Clients
ERC20 Support
Lumera Precompiles
PrecompileClientwrappers for read-only calls and state-changing sends.Client.EVM.Action,Client.EVM.Supernode, andClient.EVM.Wasm.Transaction Building Refactor
TxBuildOptionsfor explicit transaction control, including multi-message support, manual account number/sequence, gas limit overrides, simulation skipping, gas adjustment, and custom fees.PrepareTx,SignPreparedTx, andBuildAndSignTxWithOptions.BroadcastAndWaitfor broadcast plus inclusion wait.BuildAndSignTxandBuildAndSignTxWithGasAdjustmenthelpers.uint64toint64overflow regressions.Crypto and Keyring
pkg/crypto/ethsecp256k1implementation withgithub.com/cosmos/evm/crypto/ethsecp256k1.Configuration and Dependencies
replacedirectives commented out for release safety.Documentation, Examples, and Changelog
CHANGELOG.mdwith the newv1.2.0EVM-support entry and historical release notes.Cleanup and Fixes
blockchain/messages.go..github/copilot-instructions.mdfor Go 1.26.2.Tests and Validation
Added or expanded unit coverage for:
Local validation run on this branch:
go test ./...go vet ./...make lint